﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace Wolfpack.Contrib.Checks.Powershell
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class RunspaceConfigurationFactoryBase : IRunspaceConfigurationFactory
    {
        private readonly IEnumerable<string> _snapInNames;

        /// <summary>
        /// Initializes a new instance of the <see cref="RunspaceConfigurationFactoryBase"/> class.
        /// </summary>
        protected RunspaceConfigurationFactoryBase()
        {
            _snapInNames = Enumerable.Empty<string>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RunspaceConfigurationFactoryBase"/> class.
        /// </summary>
        /// <param name="snapInNames">The snap in names.</param>
        protected RunspaceConfigurationFactoryBase(IEnumerable<string> snapInNames)
        {
            if (snapInNames == null)
            {
                throw new ArgumentNullException("snapInNames");
            }

            _snapInNames = snapInNames;
        }

        /// <summary>
        /// Gets the snap in names.
        /// </summary>
        protected IEnumerable<string> SnapInNames
        {
            get { return _snapInNames; }
        }

        /// <summary>
        /// Creates the <see cref="RunspaceConfiguration"/>.
        /// </summary>
        /// <returns></returns>
        public abstract RunspaceConfiguration Create();

        /// <summary>
        /// Creates the runspace configuration based the specified snapin names.
        /// </summary>
        /// <returns>
        /// A configured <see cref="RunspaceConfiguration"/> with all the specified
        /// snapins loaded.
        /// </returns>
        /// <exception cref="SnapInLoadException">
        /// </exception>
        /// <remarks>
        /// Really, the key should not be responsible for creating
        /// the <see cref="RunspaceConfiguration"/>.
        /// </remarks>
        protected RunspaceConfiguration CreateRunspaceConfiguration()
        {
            PSSnapInException pSSnapInException = null;

            RunspaceConfiguration configuration = RunspaceConfiguration.Create();
            foreach (string snapIn in SnapInNames)
            {
                try
                {
                    configuration.AddPSSnapIn(snapIn, out pSSnapInException);
                    // not sure what it means if we get an exception back from 
                    // the AddPSSnapIn method call. Did the snapin load throw
                    // an exception? For example, a referenced assembly could
                    // not be found.
                }
                catch (PSArgumentException exception)
                {
                    // PSArgumentException gets thrown when the snapin does not exist
                    SnapInLoadException e = new SnapInLoadException(snapIn, exception);
                    throw e;
                }
            }

            return configuration;
        }

    }
}